
// ===============================================================================================================
// -*- C++ -*-
//
// Common.hpp - Common includes and definition for the application.
//
// Copyright (c) 2011 Guilherme R. Lampert
// guilherme.ronaldo.lampert@gmail.com
//
// This code is licenced under the MIT license.
//
// This software is provided "as is" without express or implied
// warranties. You may freely copy and compile this source into
// applications you distribute provided that the copyright text
// above is included in the resulting source code.
//
// ===============================================================================================================

#ifndef __COMMON_HPP__
#define __COMMON_HPP__

#if defined (_MSC_VER)
#pragma warning (disable: 4996) // Disable the CRT lib deprecation warning.
#pragma warning (disable: 4290) // Exception specification ignored warning.
#pragma warning (disable: 4505) // Unreferenced local function removed.
#pragma warning (disable: 4201) // Nameless struct/union.
#endif

// C++ std includes
#include <cstdlib>
#include <cstdio>
#include <string>
#include <new>

// Local includes
#include <OpenGL.hpp>
#include <Log.hpp>

// SIMD Extensions intrinsics. (Set this to zero to disable)
#define ENABLE_SSE_INTRINSICS 1

#if (ENABLE_SSE_INTRINSICS)
#define SSE_ALIGN(x) __declspec(align(16)) x
#include <xmmintrin.h>
#else
#define SSE_ALIGN(x) x
#endif // ENABLE_SSE_INTRINSICS

// ==== Helper Macros ====

/// I use this to get random positions for the game objects
#define RandCoord(x) (static_cast<float>(rand()) / RAND_MAX * (x))

/// Packs 3 color bytes inside an integer. The last channel is set to 255.
#define PackRGB(r, g, b) (static_cast<unsigned int>(((0xff << 24) | (((b) & 0xff) << 16) | (((g) & 0xff) << 8) | ((r) & 0xff))))

/// Packs 4 color bytes inside an integer.
#define PackRGBA(r, g, b, a) (static_cast<unsigned int>((((a) & 0xff) << 24) | (((b) & 0xff) << 16) | (((g) & 0xff) << 8) | ((r) & 0xff)))

// ==== Misc Functions ====

/// Return the number of frames per second.
/// Must be called inside the rendering loop, every time.
int CalcFPS(void);

/// Returns the elapsed microseconds since the last call to the function.
float GetElapsedMilliseconds(void);

/// Returns the elapsed seconds since the last call to the function.
float GetElapsedSeconds(void);

/// Prints an error message to the system message box.
void SysErrorMessage(const char * format, ...);

/// Prints an warning message to the system message box.
void SysWarningMessage(const char * format, ...);

/// Prints a formatted message to the system message box.
void SysOutputMessage(const char * caption, const char * format, ...);

/// Allocate bytes from the program heap.
void * MemAlloc(size_t numBytes, size_t alignment = 16);

/// Free bytes allocated by MemAlloc(). If the pointer is null, nothing is done.
void MemFree(void * memory);

/// Custom operator new that uses my own memory allocator.
void * operator new (size_t numBytes);

/// Custom operator new[] that uses my own memory allocator.
void * operator new[] (size_t numBytes);

/// Custom operator delete that uses my own memory allocator.
void operator delete (void * memory);

/// Custom operator delete[] that uses my own memory allocator.
void operator delete[] (void * memory);

// ==== Inlines ====

/// Checks if a key is down. Uses the windows virtual keys
static inline int KeyDown(int key)
{
	return ((GetAsyncKeyState(key) & 0x8000) ? 1 : 0);
}

/// Checks if a key is up. Uses the windows virtual keys
static inline int KeyUp(int key)
{
	return ((GetAsyncKeyState(key) & 0x8000) ? 0 : 1);
}

/// Swap without checking.
template<typename T> static inline void SwapFast(T & lhs, T & rhs)
{
	T tmp = lhs;
	lhs = rhs;
	rhs = tmp;
}

// ==== Constructors ====

template<typename T>
	static inline void Construct(T * ptr)
{
	::new(reinterpret_cast<void *>(ptr)) T;
}

template<typename T, typename X>
	static inline void Construct(T * ptr, const X & arg)
{
	::new(reinterpret_cast<void *>(ptr)) T(arg);
}

template<typename T, typename X, typename Y>
	static inline void Construct(T * ptr, const X & arg0, const Y & arg1)
{
	::new(reinterpret_cast<void *>(ptr)) T(arg0, arg1);
}

template<typename T, typename X, typename Y, typename Z>
	static inline void Construct(T * ptr, const X & arg0, const Y & arg1, const Z & arg2)
{
	::new(reinterpret_cast<void *>(ptr)) T(arg0, arg1, arg2);
}

// ==== Destructor ====

template<typename T>
	static inline void Destroy(T * ptr)
{
	ptr->~T();
}

#endif // __COMMON_HPP__